#ifndef BLOCK_H
#define BLOCK_H

#include <iostream>

using namespace std;

#include "Disk.h"
#include "BlockException.h"
#include "strings.h"


class Block{

 private:
  
  int m_blockNumber;

  unsigned char* m_buffer;

  
 public:


  /**
   *creates new block with a new block number and buffer with size length
   *param: blockNumber = the new block number
   *length = the length of the data buffer
   *return: none
   */
  Block(int blockNumber, int length){
    m_blockNumber = blockNumber;
    m_buffer = new unsigned char[Disk::DEFAULT_BLOCK_SIZE];
    bzero(m_buffer, Disk::DEFAULT_BLOCK_SIZE);
    cout<< m_buffer << "\n";

  }

  /**
   *builds a block object by reading from disk
   *param: blockNumber = a block position from 0 to disk length - 1
   *param: disk = pointer to the disk to read from
   *return: none
   */
  Block(int blockNumber, Disk *disk){
    if(blockNumber >= 0 && blockNumber < disk->numberOfBlocks()){
      unsigned char temp[Disk::DEFAULT_BLOCK_SIZE];
      m_buffer = new unsigned char[Disk::DEFAULT_BLOCK_SIZE];
      bool suc = disk->ReadBlock(blockNumber, temp);
      if(suc == true){
//	if(temp[0] != '\0'){
          if(true){
	  m_blockNumber = blockNumber;
	  for(int i= 0; i < Disk::DEFAULT_BLOCK_SIZE; i++){
	    m_buffer[i] = temp[i];
	  }	  
	}
	else{
	  throw BlockException();
	}
      }
      else{
       	throw BlockException();
      }
    } 
    else{
      throw BlockException();
    }
  }

  /**
   *Block destructor
   *param: none
   *return: none
   */
  ~Block(){
 //     delete [] m_buffer;
  }

  /**
   *Creates new block with specified length and sets node number to zero
   *param: length = length of buffer
   *returns: none
   */
  Block(int length){
    m_blockNumber = 0;
    m_buffer = new unsigned char[Disk::DEFAULT_BLOCK_SIZE];
    bzero(m_buffer, Disk::DEFAULT_BLOCK_SIZE);
    
  }

  /**
   *Clears the data buffer
   *param: none
   *return: none
   */
    void ClearBuffer(){
      bzero(m_buffer, Disk::DEFAULT_BLOCK_SIZE);
    }
    /**
     *accesor for blockNumber
     *param: none
     *return: the blockNumber
     */
    int GetBlockNumber(){
      return m_blockNumber;
    }

    /**
     *mutator for blockNumber
     *param: number = the new value for blockNumber
     *return: none
     */
    void SetBlockNumber(int number){
      m_blockNumber = number;
    }

 
    /**
     *Writes buffer to disk
     *param: the pointer to the disk to be written to
     *return: true on success
     */
    bool Write(Disk *disk){
      if(disk->WriteBlock(m_blockNumber, m_buffer)){
	return true;
      }
      else{
	return false;
      }
    }

    /**
     *gets a reference to m_buffer
     *param: none
     *return: pointer to buffer
     */
    unsigned char* GetBuffer(){
      return m_buffer;
    }

    /**
     *mutator for m_buffer
     *NOTE: Makes sure the buffer being passed in is dynamically allocated
     *and size 512
     *param: the new reference for m_buffer
     *return: none
     */
    void SetBuffer(unsigned char* buffer){
      if(m_buffer != buffer){
	delete [] m_buffer;
	m_buffer = buffer;
      }
    }

    /**
     *sets pointer at 4 byte location
     *param: pointer = the value of pointer to be set 
     *param: location = the 4 byte location to be set
     *return: none
     */   
    void SetPointer(int pointer, int location){
      if(location >= 0 && location < (Disk::DEFAULT_BLOCK_SIZE/4)){
	int position = location * 4;
	int* point = (int*)&m_buffer[position];
	*point = pointer;
      }
      else{
	cout<< "Invalid location\n";
      }
    }

  /**
   *gets pointer at location
   *param: location = the 4 byte location in the buffer
   *return: returns the integer pointer value
   */
  int GetPointer(int location){
      if(location >= 0 && location < (Disk::DEFAULT_BLOCK_SIZE/4)){
	int position = location * 4;
	int* point = (int*)&m_buffer[position];
	return *point;
      }
      else{
	cout<< "Invalid Location\n";
	return -1;
      }
  }

  /**
   *prints buffer to stream
   *param: none
   *return: none
   */
  void Print(){
    cout<< m_buffer << "\n";
  }


};




#endif
